module ram #(parameter W=16) (
  input         clk,
  input         rst,
  input  [ 1:0] htrans,
  input         hsel,
  input         hwrite,
  input [W-1:0] haddr,
  input  [ 2:0] hsize,
  input  [31:0] hwdata,
  output        hready,
  output        hresp,
  output [31:0] hrdata,

  input         inst_addr_valid,
  input [W-1:2] inst_addr,
  output        inst_data_valid,
  output [31:0] inst_data
);

reg hready;
reg hrdata;
reg inst_data_valid;

localparam S_IDLE = 0;
localparam S_READ = 1;

reg  [ 1:0] state;
reg [W-1:0] haddr_r;
reg         we_r;
reg  [ 2:0] hsize_r;

wire [ 3:0] bram_wea_pre_rot;
wire [ 3:0] bram_wea;
wire [31:0] bram_douta;
wire[W-1:2] bram_addra;

// instruction
always @(posedge clk) begin
  inst_data_valid <= rst ? 1'b0 : inst_addr_valid;
end

// blcok ram write enable
always @(posedge clk) begin
  if (rst) begin
    we_r <= 1'b0;
  end else begin
    we_r <= hwrite & htrans[1];
  end
  haddr_r <= haddr;
  hsize_r <= hsize;
end

// FSM
always @(posedge clk) begin
  if (rst) begin
    state <= 1<<S_IDLE;
    hready <= 1'b1;
  end else begin
    case (1'b1)
      state[S_IDLE]: begin
        if (htrans[1] & ~hwrite) begin
          hready <= 1'b0;
          state <= 1<<S_READ;
        end
      end
      state[S_READ]: begin
        hready <= 1'b1;
        hrdata <= bram_douta >> {haddr_r[1:0],3'b0};
        state <= 1<<S_IDLE;
      end
    endcase
  end
end

assign hresp = 1'b0;
assign bram_wea_pre_rot =
  {4{hsize_r == 3'b000}} & {3'b000,we_r} |
  {4{hsize_r == 3'b001}} & {2'b00,{2{we_r}}} |
  {4{hsize_r == 3'b010}} & {4{we_r}};
assign bram_wea = bram_wea_pre_rot << haddr[1:0];
assign bram_addra = we_r ? haddr_r[W-1:2] : haddr[W-1:2];

`ifdef USE_GENERIC_LIB
generic_blk_mem #(.DEPTH(W-2))
`else
blk_mem_gen_v7_3
`endif
blk_mem(
  .clka(clk),
  .wea(bram_wea),
  .addra(bram_addra),
  .dina(hwdata),
  .douta(bram_douta),
  .clkb(clk),
  .enb(inst_addr_valid),
  .web(4'b0),
  .addrb(inst_addr),
  .dinb(32'b0),
  .doutb(inst_data)
);

endmodule
